/*-------------------------------------------------------------------------
 *
 * jsonpath.h
 *	 jsonpath数据类型的定义
 *
 * Copyright (c) 2019-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	src/include/utils/jsonpath.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef JSONPATH_H
#define JSONPATH_H

#include "fmgr.h"
#include "nodes/pg_list.h"
#include "utils/jsonb.h"

typedef struct
{
	int32		vl_len_;		/* varlena 头部（请勿直接触摸！） */
	uint32		header;			/* 版本和标志（见下文） */
	char		data[FLEXIBLE_ARRAY_MEMBER];
} JsonPath;

#define JSONPATH_VERSION	(0x01)
#define JSONPATH_LAX		(0x80000000)
#define JSONPATH_HDRSZ		(offsetof(JsonPath, data))

#define DatumGetJsonPathP(d)			((JsonPath *) DatumGetPointer(PG_DETOAST_DATUM(d)))
#define DatumGetJsonPathPCopy(d)		((JsonPath *) DatumGetPointer(PG_DETOAST_DATUM_COPY(d)))
#define PG_GETARG_JSONPATH_P(x)			DatumGetJsonPathP(PG_GETARG_DATUM(x))
#define PG_GETARG_JSONPATH_P_COPY(x)	DatumGetJsonPathPCopy(PG_GETARG_DATUM(x))
#define PG_RETURN_JSONPATH_P(p)			PG_RETURN_POINTER(p)

#define jspIsScalar(type) ((type) >= jpiNull && (type) <= jpiBool)

/*
 * jsonpath 表达式的所有节点类型
 */
typedef enum JsonPathItemType
{
	jpiNull = jbvNull,			/* NULL 字面量 */
	jpiString = jbvString,		/* 字符串字面量 */
	jpiNumeric = jbvNumeric,	/* 数字字面量 */
	jpiBool = jbvBool,			/* 布尔字面量：TRUE 或 FALSE */
	jpiAnd,						/* 谓词 && 谓词 */
	jpiOr,						/* 谓词 || 谓词 */
	jpiNot,						/* ! 谓词 */
	jpiIsUnknown,				/* (谓词) 为未知 */
	jpiEqual,					/* expr == expr */
	jpiNotEqual,				/* expr != expr */
	jpiLess,					/* expr < expr */
	jpiGreater,					/* expr > expr */
	jpiLessOrEqual,				/* expr <= expr */
	jpiGreaterOrEqual,			/* expr >= expr */
	jpiAdd,						/* expr + expr */
	jpiSub,						/* expr - expr */
	jpiMul,						/* expr * expr */
	jpiDiv,						/* expr / expr */
	jpiMod,						/* expr % expr */
	jpiPlus,					/* + expr */
	jpiMinus,					/* - expr */
	jpiAnyArray,				/* [*] */
	jpiAnyKey,					/* .* */
	jpiIndexArray,				/* [下标，...] */
	jpiAny,						/* .** */
	jpiKey,						/* .key */
	jpiCurrent,					/* @ */
	jpiRoot,					/* $ */
	jpiVariable,				/* $变量 */
	jpiFilter,					/* ? (谓词) */
	jpiExists,					/* EXISTS (expr) 谓词 */
	jpiType,					/* .type() 项目方法 */
	jpiSize,					/* .size() 项目方法 */
	jpiAbs,						/* .abs() 项目方法 */
	jpiFloor,					/* .floor() 项目方法 */
	jpiCeiling,					/* .ceiling() 项目方法 */
	jpiDouble,					/* .double() 项目方法 */
	jpiDatetime,				/* .datetime() 项方法 */
	jpiKeyValue,				/* .keyvalue() 项方法 */
	jpiSubscript,				/* 数组下标：'expr' 或 'expr TO expr' */
	jpiLast,					/* LAST 数组下标 */
	jpiStartsWith,				/* 开始于 谓词 */
	jpiLikeRegex,				/* LIKE_REGEX 谓词 */
} JsonPathItemType;

/* XQuery 正则模式标志用于 LIKE_REGEX 谓词 */
#define JSP_REGEX_ICASE		0x01	/* i 标志，不区分大小写 */
#define JSP_REGEX_DOTALL	0x02	/* s 标志，点匹配换行符 */
#define JSP_REGEX_MLINE		0x04	/* m 标志，^/$ 在换行符处匹配 */
#define JSP_REGEX_WSPACE	0x08	/* x 标志，忽略模式中的空格 */
#define JSP_REGEX_QUOTE		0x10	/* q 标志，无特殊字符 */

/*
 * 支持解析/构建二进制值的函数。
 * 与许多其他表达的表示不同，第一个/主要节点不是操作，而是表达的左操作数。
 * 这允许在 jsonb 结构中实现廉价的跟随路径下降，
 * 然后执行与右操作数的操作。
 */

typedef struct JsonPathItem
{
	JsonPathItemType type;

	/* 从基位置到下一个节点 */
	int32		nextPos;

	/*
	 * 指向 JsonPath 值的当前节点的指针，当前的所有位置
	 * 相对于这个基准
	 */
	char	   *base;

	union
	{
		/* 经典运算符有两个操作数：与，或等 */
		struct
		{
			int32		left;
			int32		right;
		}			args;

		/* 任何一元操作 */
		int32		arg;

		/* jpiIndexArray 的存储：数组的索引 */
		struct
		{
			int32		nelems;
			struct
			{
				int32		from;
				int32		to;
			}		   *elems;
		}			array;

		/* jpiAny：级别 */
		struct
		{
			uint32		first;
			uint32		last;
		}			anybounds;

		struct
		{
			char	   *data;	/* 对于布尔值、数值和字符串/键 */
			int32		datalen;	/* 仅针对字符串/键填充 */
		}			value;

		struct
		{
			int32		expr;
			char	   *pattern;
			int32		patternlen;
			uint32		flags;
		}			like_regex;
	}			content;
} JsonPathItem;

#define jspHasNext(jsp) ((jsp)->nextPos > 0)

extern void jspInit(JsonPathItem *v, JsonPath *js);
extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos);
extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a);
extern void jspGetArg(JsonPathItem *v, JsonPathItem *a);
extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a);
extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a);
extern Numeric jspGetNumeric(JsonPathItem *v);
extern bool jspGetBool(JsonPathItem *v);
extern char *jspGetString(JsonPathItem *v, int32 *len);
extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
								 JsonPathItem *to, int i);

extern const char *jspOperationName(JsonPathItemType type);

/*
 * 解析支持的数据结构。
 */

typedef struct JsonPathParseItem JsonPathParseItem;

struct JsonPathParseItem
{
	JsonPathItemType type;
	JsonPathParseItem *next;	/* 路径中的下一个 */

	union
	{

		/* 经典运算符有两个操作数：与，或等 */
		struct
		{
			JsonPathParseItem *left;
			JsonPathParseItem *right;
		}			args;

		/* 任何一元操作 */
		JsonPathParseItem *arg;

		/* jpiIndexArray 的存储：数组的索引 */
		struct
		{
			int			nelems;
			struct
			{
				JsonPathParseItem *from;
				JsonPathParseItem *to;
			}		   *elems;
		}			array;

		/* jpiAny：级别 */
		struct
		{
			uint32		first;
			uint32		last;
		}			anybounds;

		struct
		{
			JsonPathParseItem *expr;
			char	   *pattern;	/* 可能不以空字符结束 */
			uint32		patternlen;
			uint32		flags;
		}			like_regex;

		/* scalars */
		Numeric numeric;
		bool		boolean;
		struct
		{
			uint32		len;
			char	   *val;	/* 可能不以空字符结束 */
		}			string;
	}			value;
};

typedef struct JsonPathParseResult
{
	JsonPathParseItem *expr;
	bool		lax;
} JsonPathParseResult;

extern JsonPathParseResult *parsejsonpath(const char *str, int len);

extern int	jspConvertRegexFlags(uint32 xflags);

#endif
